﻿using CodeSmith.Data.Linq;
using ezCloud.Api.Common;
using ezCloud.Api.Models;
using ezCloud.Data;
using Microsoft.AspNet.Identity;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Linq;
using System.Data.SqlTypes;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Script.Serialization;

using static ezCloud.Api.Controllers.RoomController;

namespace ezCloud.Api.Controllers
{
    [ApiAuthorize]
    [RoutePrefix("api/app")]
    public class AppController : ApiController
    {
        private Common.MemoryCacher memCache = new Common.MemoryCacher();

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GlobalData")]
        public async Task<IHttpActionResult> getGlobalData()

        {
            var context = new ezCloudDataContext();
            var memcache = new MemoryCacher();
            

            var user = Common.UserUtitily.getUserProfile();

            var lastCache = memCache.GetValue("AppGLOBAL_" + user.HotelId);
            if (lastCache != null)
            {
                //return Ok(lastCache);
            }
            var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.IsHidden == false)
                 .Future().ToList().OrderBy(o => o.OrderNumber);
            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false).
                 OrderBy(o => o.OrderNumber).
                 Select(rm => new
                 {
                     Room = rm,
                     RoomType = rm.RoomTypes,
                     rm.RoomRepairList
                 }).ToList();
            var roomTypes = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId && roomType.IsDeleted == false && roomType.IsHidden == false).ToList();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
             

            var paymentMethods = context.PaymentMethods.ToList(); //results2.GetResult<PaymentMethods>().ToList();
            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }
            if (paymentMethods.Count == 0)
            {
                //Auto generate payment methods
                var cash = new PaymentMethods();
                cash.PaymentMethodName = "CASH";
                cash.PaymentMethodDescription = "CASH_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(cash);
                var credit = new PaymentMethods();
                credit.PaymentMethodName = "CREDIT";
                credit.PaymentMethodDescription = "CREDIT_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(credit);
                var banktransfer = new PaymentMethods();
                banktransfer.PaymentMethodName = "BANK_TRANSFER";
                banktransfer.PaymentMethodDescription = "BANK_TRANSFER";
                context.PaymentMethods.InsertOnSubmit(banktransfer);
                var cityledger = new PaymentMethods();
                cityledger.PaymentMethodName = "CITY_LEDGER";
                cityledger.PaymentMethodDescription = "CITY_LEDGER";
                context.PaymentMethods.InsertOnSubmit(cityledger);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            var MoneyName = defaultCurrency.MoneyName;
            var FormatCurrency = Math.Abs(Convert.ToDecimal(1111111)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals("VND"));

            var statusColors = context.StatusColors.Where(sc => sc.HotelId == user.HotelId).ToList();
            var cache = new
            { 
                roomList = roomList,
                roomTypes = roomTypes,
                rooms = rooms,
                paymentMethods = paymentMethods,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    FormatCurrency = FormatCurrency,
                    CurrencyInfo = defaultCurrency.Currencies
                },
                statusColors = statusColors,
                ezReferralPrograms = context.EzReferralPrograms.Where(ez => ez.EzReferralProgramCode == "REFERRALPROGRAM").FirstOrDefault()
            };
            memCache.Add("AppGLOBAL_" + user.HotelId, cache, DateTimeOffset.UtcNow.AddHours(1)); 
            return Ok(cache);
        }

        public class CMAvailabilityMatrixModel
        {
            public CMAvailabilityMatrixs CMAvailabilityMatrixs { get; set; }
            public string ActionName { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessSaveAvailabilityMatrixData")]
        public async Task<IHttpActionResult> ProcessSaveAvailabilityMatrixData(CMAvailabilityMatrixModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            switch (model.ActionName)
            {
                case "AVAILABILITY":
                    if (model.CMAvailabilityMatrixs != null && model.CMAvailabilityMatrixs.CMAvailabilityMatrixId != 0)
                    {
                        var currentCMAV = context.CMAvailabilityMatrixs.FirstOrDefault(av => av.HotelId == user.HotelId && av.CMAvailabilityMatrixId == model.CMAvailabilityMatrixs.CMAvailabilityMatrixId);
                        if (currentCMAV != null)
                        {
                            currentCMAV.CanBeSold = model.CMAvailabilityMatrixs.CanBeSold;
                            currentCMAV.Rate = model.CMAvailabilityMatrixs.Rate;
                            currentCMAV.MinLOS = model.CMAvailabilityMatrixs.MinLOS;
                            currentCMAV.MaxLOS = model.CMAvailabilityMatrixs.MaxLOS;
                            currentCMAV.Cta = model.CMAvailabilityMatrixs.Cta;
                            currentCMAV.Ctd = model.CMAvailabilityMatrixs.Ctd;
                            currentCMAV.StopSell = model.CMAvailabilityMatrixs.StopSell;
                            currentCMAV.LastModifiedDate = DateTime.UtcNow;
                            currentCMAV.LastModifiedUserId = user.UserId;
                        }
                    }
                    else
                    {
                        model.CMAvailabilityMatrixs.HotelId = user.HotelId;
                        model.CMAvailabilityMatrixs.CreatedDate = DateTime.UtcNow;
                        model.CMAvailabilityMatrixs.CreatedUserId = user.UserId;
                        context.CMAvailabilityMatrixs.InsertOnSubmit(model.CMAvailabilityMatrixs);
                    }

                    var newCMBackgroundJob = new CMBackgroundJobs
                    {
                        HotelId = user.HotelId,
                        CMRoomTypeMappingId = model.CMAvailabilityMatrixs.CMRoomTypeMappingId,
                        StartDate = model.CMAvailabilityMatrixs.MatrixDate,
                        EndDate = model.CMAvailabilityMatrixs.MatrixDate,
                        ActionStatus = 0,
                        ActionName = model.ActionName,
                        ActionValue = model.CMAvailabilityMatrixs.CanBeSold.ToString(),
                        CreatedDate = DateTime.UtcNow,
                        CreatedUserId = user.UserId
                    };
                    context.CMBackgroundJobs.InsertOnSubmit(newCMBackgroundJob);
                    break;
            }

            context.SubmitChanges();
            Elastic.IndexLastAudit(context);

            //send room available to CM
            //if (await Common.ChannelManagerBackgroundJob.ChannelManagerBackgroundJobScheduler())
            //{
            var cache = new
            {
                status = 200,
                mess = "Success",
                //roomList = roomList,
                //rooms = roomsList,
                //roomBookingList = roomBookingList,
                //BookingList = bookingList,
                //roomTypes = roomTypes,
                //RelatedPayments = allRelatedPayments,
                //RoomMoves = allRoomMoves,
                //RoomExtraServicesList = allRoomExtraServiceList,
                //RoomExtraServiceItemsList = allRoomExtraServiceItemsList
                //unassignRoom = UnassignRoom,
            };
            return Ok(cache);
            //}
            //else
            //{
            //    return BadRequest("CAN_NOT_SEND_ROOM_AVAILABLE_TO_CM");
            //}


        }
        public class Traveller
        {
            public string Fullname;
            public int TravellerId = 0;
        }

        public class NewRoom
        {
            /*public string BookingStatus { get; set; }
            public bool IsGroupMaster { get; set; }
            public bool IsGroup { get; set; }
            public string GroupColor { get; set; }
            public DateTime ArrivalDate { get; set; }
            public DateTime DepartureDate { get; set; }
            public int Adults { get; set; }
            public int Child { get; set; }
            public EntitySet<Reservations> Reservations { get; set; }
            public string Note { get; set; }
            public decimal Price { get; set; }
            public EntitySet<Traveller> Travellers { get; set; }
            public EntitySet<RoomPrices> RoomPrices { get; set; }
            public int RoomId { get; set; }
            public int RoomTypeId { get; set; }
            public int ReservationRoomId { get; set; }
            public EntitySet<Travellers> TravellersList { get; set; }
            public bool Foc { get; set; } 
            public float DiscountPercentage { get; set; }
            public int RoomPriceId { get; set; }
            public int ReservationRoomNumber { get; set; }
            public EntitySet<RoomMove> RoomMoveList { get; set; }*/
            public string BookingStatus;
            public bool IsGroupMaster;
            public bool IsGroup;
            public string GroupColor;
            public int? Adults = 0;
            public DateTime ArrivalDate;
            public int? Child = 0;
            public DateTime DepartureDate;
            public Reservations Reservations;
            public string Note;
            public decimal Price = 0;
            public Traveller Travellers;
            public RoomPrices RoomPrices;
            public int? RoomId = 0;
            public int? RoomTypeId = 0;
            public int? ReservationRoomId = 0;
            public EntitySet<Travellers> TravellersList;
            public RoomTypes RoomTypes; 
            public bool Foc;
            public double DiscountPercentage;
            public decimal DiscountFlat = 0;
            public int? RoomPriceId = 0;
            public int? ReservationRoomNumber = 0;
            public EntitySet<RoomMove> RoomMoveList;

        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomTimeline")]
        public async Task<IHttpActionResult> getTimeline(DateTime date, int duration)
        {
            var memcache = new MemoryCacher();
            var user = Common.UserUtitily.getUserProfile();
            var cacheKey = "AppTIMELINE_" + user.HotelId + "_" + string.Format("{0:yyyyMMdd}", date) + "_" + duration;
            var timelineCache = memcache.GetValue(cacheKey);
            if (timelineCache != null)
                return Ok(timelineCache);
            var context = new ezCloudDataContext();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            date = date.AddMinutes(-currentHotel.TimeZoneOffset);
            var endDate = date.AddDays(duration);

            var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId != null && (DateTime)r.ArrivalDate <= endDate && (DateTime)r.DepartureDate >= date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new 
                    {
                        r.BookingStatus,
                        r.Adults,
                        r.ArrivalDate,
                        r.Child,
                        r.DepartureDate,
                        r.Reservations,
                        Travellers = new
                        {
                            r.Travellers.Fullname,
                            r.Travellers.TravellerId
                        },
                        r.RoomId,
                        r.ReservationRoomId,
                        r.TravellersList,
                        r.Foc,
                        r.DiscountPercentage,
                        r.DiscountFlat,
                        r.RoomPriceId,
                    }).ToList();

            /*var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.IsHidden == false)
                 .Future().ToList();*/
            var RoomRepairList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false).
                 Select(rm => new
                 {
                     //Room = rm,
                     //RoomType = rm.RoomTypes,
                     rm.RoomRepairList
                 }).ToList();
            //var roomTypes = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId).ToList();


             
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId &&
                rr.BookingStatus != "CANCELLED" && ((rr.ArrivalDate <= endDate && rr.DepartureDate >= date)))
                .Select(rr => new NewRoom
                {
                    BookingStatus = rr.BookingStatus,
                    IsGroupMaster = (bool) (rr.IsGroupMaster == null ? false : rr.IsGroupMaster),
                    IsGroup = (bool) (rr.Reservations.IsGroup == null ? false : rr.Reservations.IsGroup),
                    GroupColor = rr.Reservations.Color,
                    Adults = rr.Adults,
                    ArrivalDate = (DateTime) rr.ArrivalDate,
                    Child = rr.Child,
                    DepartureDate = (DateTime) rr.DepartureDate,
                    //rr.Rooms,
                    Reservations = rr.Reservations,
                    Note = rr.Note,
                    Price = rr.Price,
                    Travellers = new Traveller
                    {
                        Fullname = rr.Travellers.Fullname,
                        TravellerId = rr.Travellers.TravellerId
                    },
                    RoomPrices = rr.RoomPrices,
                    RoomTypes = rr.RoomTypes,
                    RoomId = (int) rr.RoomId,
                    RoomTypeId = (int) rr.RoomTypeId,
                    ReservationRoomId= rr.ReservationRoomId,
                    TravellersList =   rr.TravellersList,
                    //rr.CancelReason,
                    Foc = rr.Foc,
                    DiscountPercentage = rr.DiscountPercentage,
                    DiscountFlat = rr.DiscountFlat,
                    RoomPriceId = (int) rr.RoomPriceId,
                    //rr.RoomExtraServicesList,
                    //rr.RoomExtraServiceItemsList,
                    //rr.,
                    //rr.CreatedDate,
                    //rr.CreatedUserId,
                    //rr.CheckInDate,
                    //rr.CheckInUserId,
                    //rr.CheckOutDate,
                    //rr.CheckOutUserId,
                    //rr.CancelDate,
                    //rr.CancelUserId,
                    ReservationRoomNumber = (int) rr.ReservationRoomNumber,
                    RoomMoveList = rr.RoomMoveList
                }).ToList();

            //var roomsList = rooms;
            /*
            List<int> rrIdList = new List<int>();

            foreach (var rr in reservationRooms)
            {
                rrIdList.Add(rr.ReservationRoomId);
            }
            */
            //var RepairList = new ArrayList();
            foreach ( var repair in RoomRepairList)
            {
                foreach (var repa in repair.RoomRepairList)
                {
                    if (repa.IsDeleted == false )
                    {
                        //RepairList.Add(repa);
                        NewRoom newRoom = new NewRoom();
                        var temp = new ReservationRooms();

                        newRoom.DepartureDate = repa.RepairEndDate.Value;
                        newRoom.ArrivalDate = repa.RepairStartDate.Value;
                        newRoom.RoomId = repa.RoomId.Value;
                        newRoom.Note = repa.RepairReason;
                        newRoom.BookingStatus = "REPAIR";
                        reservationRooms.Add(newRoom);
                    }

                }
            }
            //var allRelatedRoomExtraServicesQuery = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRelatedPaymentsQuery = context.Payments.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRoomMovesQuery = context.RoomMove.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRoomExtraServiceItemsQuery = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));


            //var results2 = context.ExecuteQuery(allRelatedRoomExtraServicesQuery, allRelatedPaymentsQuery, allRoomMovesQuery, allRoomExtraServiceItemsQuery);
            //var allRoomExtraServiceList = results2.GetResult<RoomExtraServices>().ToList();
            //var allRelatedPayments = results2.GetResult<Payments>().ToList();
            //var allRoomMoves = results2.GetResult<RoomMove>().ToList();
            //var allRoomExtraServiceItemsList = results2.GetResult<RoomExtraServiceItems>().ToList();

            var cache = new
            {
                reservationRooms = reservationRooms,
                //RoomRepairList = RepairList, 
            //roomList = roomList,
            //rooms = roomsList,
            //roomBookingList = roomBookingList,
            //BookingList = bookingList,
            //roomTypes = roomTypes,
            //RelatedPayments = allRelatedPayments,
            //RoomMoves = allRoomMoves,
            //RoomExtraServicesList = allRoomExtraServiceList,
            //RoomExtraServiceItemsList = allRoomExtraServiceItemsList
            //unassignRoom = UnassignRoom,
        };
            memcache.AddByHotelId(user.HotelId, cacheKey, cache, DateTimeOffset.UtcNow.AddHours(1));
            return Ok(cache);
        }



         

        /// <summary>
        ///
        /// </summary>
        /// <param name="from"></param>
        /// <returns></returns>
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("DashboardForApp")]
        public async Task<IHttpActionResult> getDashboardForApp(DateTime from)
        {
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            //var memcache = new MemoryCacher();
            var cacheKey = "AppDASHBOARD_" + user.HotelId + "_" + string.Format("{0:yyyyMMdd}", from) + "_" + 0;
            var timelineCache = memCache.GetValue(cacheKey);
            if (timelineCache != null)
                return Ok(timelineCache);

            //var lastCache = memCache.GetValue(cacheKey);
            //if (lastCache != null)
            //{
            //    return Ok(lastCache);
            //}




            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();

            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }

            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }

            var date = from.AddMinutes(-currentHotel.TimeZoneOffset);
            var datefrom = from.AddMinutes(-currentHotel.TimeZoneOffset);
            var dateto = datefrom.AddDays(1);

            DashboardApp statisDash = new DashboardApp();

            DataTable AvailableRooms = new DataTable();
            AvailableRooms = Utilities.GetAvailableRooms(datefrom, date);
            IEnumerable<DataRow> AvailableRoomsRow =
                   from order in AvailableRooms.AsEnumerable()
                   select order;

            var TotalRoomCount = (int)AvailableRoomsRow.FirstOrDefault()["AvailableRooms"];
            var TotalrepairRoomCount = (int)AvailableRoomsRow.FirstOrDefault()["RepairRooms"];

            //Get Payment
            decimal tmpTotalPayment = 0;
            tmpTotalPayment = Convert.ToDecimal(context.Payments.Where(pay => pay.HotelId == user.HotelId && pay.CreatedDate >= datefrom && pay.CreatedDate < dateto && pay.RefPaymentId == null && pay.PaymentTypeName != "DELETED").Sum(apay => apay.Amount));

            statisDash.Total_Payment = tmpTotalPayment;
            //get Revenue
            statisDash.Total_Revenue = Convert.ToDecimal(
                context.Payments.Where(p => p.HotelId == user.HotelId)
                .Join(context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.DepartureDate >= datefrom && rr.DepartureDate < dateto && rr.BookingStatus == "CHECKOUT"), p => p.ReservationRoomId, c => c.ReservationRoomId, (p, c) => new { Amount = p.Amount }).Sum(a => a.Amount)
                );

            // Lay so lieu thong ke

            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false).ToList();

            // Dem du lieu

            var listReservationRoom = context.ReservationRooms.Where(r => r.HotelId == user.HotelId).ToList();

            //var listReservationTravellers = context.ReservationTravellers.Where(rt => rt.ReservationTravellerExtraInformationList.Where(rtif => rtif.HotelId == user.HotelId && rtif.ReservationTravellerId == rt.ReservationTravellerId).Select(rt.ReservationRoomId,rtif.IsChild)).
            var listReservationTravellerExtraInformation = context.ReservationTravellerExtraInformation.Where(t => t.HotelId == user.HotelId)
               .Join(context.ReservationTravellers, rt => rt.ReservationTravellerId, rtei => rtei.ReservationTravellerId, (rt, rtei) => new { rt.ReservationTravellers.ReservationRoomId, rt.IsChild }).ToList();

            //Phòng khách đang ở
            statisDash.todayStats_roomOccupied = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Count();
            //Phòng sẽ đi trong ngày hôm nay
            statisDash.todayStats_roomDueOut = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Count();
            //Phòng đã checkin từ hôm trước đó, hôm nay vẫn ở và chưa đi
            statisDash.todayStats_roomTodayStayOver = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto).Count();
            //Phòng có trạng thái Booked, có ngày đến là ngày thống kê,  nhưng chưa đến
            statisDash.todayStats_roomArrival = listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Count();

            statisDash.todayStats_roomTotalRoomsToSell = TotalRoomCount;

            //Khách đang ở ngày hiện tại vẫn chưa đi + dự kiến đến
            statisDash.todayStats_Projected_roomOccupied = statisDash.todayStats_roomArrival + listReservationRoom.Where(r => r.ArrivalDate < datefrom && r.DepartureDate > dateto && (r.BookingStatus == "CHECKIN")).Count()
                                                + listReservationRoom.Where(r => r.ArrivalDate >= datefrom && r.ArrivalDate < dateto && r.DepartureDate >= datefrom && (r.BookingStatus == "CHECKIN")).Count();

            //Đếm số phòng đã đến trong ngày hiện tại và ngày đi lớn hơn ngày hiện tại
            statisDash.todayActivity_Arrived = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Count();
            //Đếm số phòng sẽ đến
            statisDash.todayActivity_Due_To_Arrive = statisDash.todayStats_roomArrival;
            //Đếm số phòng đã đi
            statisDash.todayActivity_Checked_Out = listReservationRoom.Where(r => r.BookingStatus == "CHECKOUT" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Count();
            //Đếm số phòng dự kiến đi
            statisDash.todayActivity_Due_Out = statisDash.todayStats_roomDueOut;
            //Đếm phòng có ngày đến=ngày đi=ngày hiện tại (chỉ lấy phòng có trạng thái CHECKIN + CHECKOUT)
            statisDash.todayActivity_Day_Use = listReservationRoom.Where(r => r.ArrivalDate >= datefrom && r.ArrivalDate < dateto && r.ArrivalDate.Value.Date == r.DepartureDate.Value.Date && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "CHECKOUT")).Count();

            //var CountAdulttt = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
            //   .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList();

            //var CountChildtt = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
            //  .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList();

            var CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            var CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN"), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            var CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });
            //var CountAduldChild1 = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN").Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            statisDash.hotelGuests_Expected_In_House_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            statisDash.hotelGuests_Expected_In_House_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());

            var Current_In_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Current_In_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Current_In_House = Current_In_Adult + Current_In_Children;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
              .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.DepartureDate >= datefrom && r.DepartureDate < dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Due_To_Checkout_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Due_To_Checkout_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Due_To_Checkout = Due_To_Checkout_Children + Due_To_Checkout_Adult;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
             .Join(listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "BOOKED" && r.ArrivalDate >= datefrom && r.ArrivalDate < dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Due_To_Arrive_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Due_To_Arrive_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Due_To_Arrive = Due_To_Arrive_Adult + Due_To_Arrive_Children;

            CountAdult = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == false)
           .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountChild = listReservationTravellerExtraInformation.Where(rt => rt.IsChild == true)
                .Join(listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto), rr => rr.ReservationRoomId, rt => rt.ReservationRoomId, (rr, rt) => new { }).ToList().Count();

            CountAduldChild = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN" && r.ArrivalDate < datefrom && r.DepartureDate > dateto).Select(o => new { o.HotelId, o.Adults, o.Child }).GroupBy(g => new { g.HotelId }).Select(s => new { Adults = s.Sum(p => p.Adults), Child = s.Sum(p => p.Child) });

            var Staying_Over_Adult = Math.Max((int)CountAdult, (int)CountAduldChild.Select(r => r.Adults).FirstOrDefault());
            var Staying_Over_Children = Math.Max((int)CountChild, (int)CountAduldChild.Select(r => r.Child).FirstOrDefault());
            var Staying_Over = Staying_Over_Adult + Staying_Over_Children;

            var Expected_In_House = Due_To_Arrive + statisDash.hotelGuests_Expected_In_House_Adult + statisDash.hotelGuests_Expected_In_House_Children;
            var Expected_In_House_Adult = Due_To_Arrive_Adult + statisDash.hotelGuests_Expected_In_House_Adult;
            var Expected_In_House_Children = Due_To_Arrive_Children + statisDash.hotelGuests_Expected_In_House_Children;

            var todayStats_roomOccupiedForecast = listReservationRoom.Where(r => r.ArrivalDate < dateto && r.DepartureDate >= datefrom && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "BOOKED" || r.BookingStatus == "CHECKOUT")).Count()
                                                - listReservationRoom.Where(r => r.ArrivalDate < datefrom && r.DepartureDate >= datefrom && r.DepartureDate < dateto && (r.BookingStatus == "CHECKIN" || r.BookingStatus == "BOOKED" || r.BookingStatus == "CHECKOUT")).Count();

            double TotaltodayStats_Projected_Occupancy = 0;
            if (statisDash.todayStats_roomTotalRoomsToSell > 0)
            {
                TotaltodayStats_Projected_Occupancy = Convert.ToDouble(todayStats_roomOccupiedForecast) / statisDash.todayStats_roomTotalRoomsToSell * 100;
            }
            statisDash.todayStats_Projected_Occupancy = Math.Round(TotaltodayStats_Projected_Occupancy, 2);

            var Dirty_Occupied = listReservationRoom.Where(r => r.BookingStatus == "CHECKIN")
                            .Join(roomList.Where(ro => ro.HouseStatus == "DIRTY"), l1 => l1.RoomId, l2 => l2.RoomId, (l1, l2) => new { }).ToList().Count();

            var Dirty_Variant = Math.Abs(roomList.Where(ro => ro.HouseStatus == "DIRTY").ToList().Count() - Dirty_Occupied);

            var retval = new
            {
                Dashboard = statisDash,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },
                Out_Of_Order = TotalrepairRoomCount,
                Total_Room_Available = TotalRoomCount,
                Dirty_Occupied = Dirty_Occupied,
                Dirty_Variant = Dirty_Variant,
                hotelGuests = new
                {
                    Current_In_House = Current_In_House
                    ,
                    Current_In_Adult = Current_In_Adult
                    ,
                    Current_In_Children = Current_In_Children
                    ,
                    Due_To_Checkout = Due_To_Checkout
                    ,
                    Due_To_Checkout_Adult = Due_To_Checkout_Adult
                    ,
                    Due_To_Checkout_Children = Due_To_Checkout_Children
                    ,
                    Due_To_Arrive = Due_To_Arrive
                    ,
                    Due_To_Arrive_Adult = Due_To_Arrive_Adult
                    ,
                    Due_To_Arrive_Children = Due_To_Arrive_Children
                    ,
                    Staying_Over = Staying_Over
                    ,
                    Staying_Over_Adult = Staying_Over_Adult
                    ,
                    Staying_Over_Children = Staying_Over_Children
                    ,
                    Expected_In_House = Expected_In_House
                    ,
                    Expected_In_House_Adult = Expected_In_House_Adult
                    ,
                    Expected_In_House_Children = Expected_In_House_Children
                },
            };
            //memCache.Add("STATUS_" + user.HotelId, retval, DateTimeOffset.UtcNow.AddHours(1));
            var cache = retval;
            memCache.AddByHotelId(user.HotelId, cacheKey, cache, DateTimeOffset.UtcNow.AddHours(1));
            return Ok(retval);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RoomStatus")]
        public async Task<IHttpActionResult> getAllRoomStatus(DateTime date)
        {
            var currentTime = DateTime.Now;
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();

            var lastCache = memCache.GetValue("AppSTATUS_" + user.HotelId);
            /*if (lastCache != null)
            {
                return Ok(lastCache);
            }*/

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            date = date.AddMinutes(-currentHotel.TimeZoneOffset);

            DataTable AvailableRooms = new DataTable();
            AvailableRooms = Utilities.GetAvailableRooms(date, date);

            var roomList = context.Rooms.Where(room => room.HotelId == user.HotelId && room.IsHidden == false && room.RoomTypes.IsHidden == false).
                Select(rm => new
                {
                    //Room = rm,
                    //RoomType = rm.RoomTypes,
                    RoomRepairList = rm.RoomRepairList.Where(rpl => rpl.IsDeleted == false && rpl.RepairStartDate > currentTime).ToList()
                }).ToList();

            //Dictionary<int, object> roomBookingList = new Dictionary<int, object>();
            //Dictionary<int, object> roomBookingList1 = new Dictionary<int, object>();

            var bookingList = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId != null && (DateTime)r.ArrivalDate > date && r.BookingStatus != "CANCELLED" && r.BookingStatus != "CHECKOUT")
                    .Select(r => new
                    {
                        r.BookingStatus,
                        r.Adults,
                        r.ArrivalDate,
                        r.Child,
                        r.DepartureDate,
                        //r.Reservations, 
                        r.RoomId,
                        r.ReservationRoomId,
                        //r.TravellersList,
                        r.Foc,
                        r.DiscountPercentage,
                        r.DiscountFlat,
                        r.RoomPriceId,
                    }).ToList();
              
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId &&
                ((rr.ArrivalDate <= date.AddDays(1) && rr.DepartureDate >= date) ||
                (rr.ArrivalDate <= date && rr.BookingStatus == "CHECKIN")))
                .Select(rr => new
                {
                    rr.BookingStatus,
                    rr.Adults,
                    rr.IsGroupMaster,
                    rr.ArrivalDate,
                    rr.Child,
                    rr.DepartureDate, 
                    rr.TravellerId, 
                    rr.RoomId,
                    rr.ReservationRoomId,
                    //rr.TravellersList,
                    //rr.PaymentsList,
                    rr.Foc,
                    rr.DiscountPercentage,
                    rr.DiscountFlat,
                    rr.RoomPriceId,
                    //rr.RoomExtraServicesList,
                    //rr.RoomExtraServiceItemsList,
                    rr.Price,
                    rr.Note,
                    rr.Reservations.Company,
                    rr.Reservations.Source,
                    rr.Reservations.Market,
                    //rr.RoomMoveList
                }).ToList();/*
            List<int> rrIdList = new List<int>();

            foreach (var rr in reservationRooms)
            {
                rrIdList.Add(rr.ReservationRoomId);
            }


            var allResExtra = context.ReservationTravellerExtraInformation.Where(etxi => etxi.HotelId == user.HotelId).Select(
                etxi => new { etxi.IsChild, etxi.ReservationTravellers.TravellerId, etxi.ReservationTravellers.ReservationRoomId }
                ).ToList();
            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
            */
            //group into batch query
            //var allRelatedRoomExtraServicesQuery = context.RoomExtraServices.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRelatedPaymentsQuery = context.Payments.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRoomMovesQuery = context.RoomMove.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));
            //var allRoomExtraServiceItemsQuery = context.RoomExtraServiceItems.Where(p => p.HotelId == user.HotelId && rrIdList.Contains((int)p.ReservationRoomId));

            //var roomTypesQuery = context.RoomTypes.Where(roomType => roomType.HotelId == user.HotelId && !roomType.IsHidden);
            var planListQuery = context.RoomPrices.Where(rp => rp.HotelId == user.HotelId);
            //var statusColorsQuery = context.StatusColors.Where(sc => sc.HotelId == user.HotelId);
            //var paymentMethodsQuery = context.PaymentMethods;
            //var remarkEventsQuery = context.RemarkEvents;
            /*var sourceListQuery = context.Source.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var companyListQuery = context.Company.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            var marketListQuery = context.Market.Where(src => src.HotelId == user.HotelId && src.IsAvailable == true);
            */
            var results2 = context.ExecuteQuery(planListQuery /*, roomTypesQuery, paymentMethodsQuery, remarkEventsQuery, statusColorsQuery, 
                                                , sourceListQuery, companyListQuery, marketListQuery,
                                                allRelatedRoomExtraServicesQuery, allRelatedPaymentsQuery, allRoomMovesQuery, allRoomExtraServiceItemsQuery
                                                */);


            //var roomTypes = results2.GetResult<RoomTypes>().ToList();
            var planList = results2.GetResult<RoomPrices>().ToList();
            //var statusColors = results2.GetResult<StatusColors>().ToList();
            //var paymentMethods = results2.GetResult<PaymentMethods>().ToList();
            //var remarkEvents = results2.GetResult<RemarkEvents>().ToList();
            /*var sourceList = results2.GetResult<Source>().ToList();
            var companyList = results2.GetResult<Company>().ToList();
            var marketList = results2.GetResult<Market>().ToList();
            var allRoomExtraServiceList = results2.GetResult<RoomExtraServices>().ToList();
            var allRelatedPayments = results2.GetResult<Payments>().ToList();
            var allRoomMoves = results2.GetResult<RoomMove>().ToList();
            var allRoomExtraServiceItemsList = results2.GetResult<RoomExtraServiceItems>().ToList();
            */
            //Data correction methods
            /*
            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }
            if (paymentMethods.Count == 0)
            {
                //Auto generate payment methods
                var cash = new PaymentMethods();
                cash.PaymentMethodName = "CASH";
                cash.PaymentMethodDescription = "CASH_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(cash);
                var credit = new PaymentMethods();
                credit.PaymentMethodName = "CREDIT";
                credit.PaymentMethodDescription = "CREDIT_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(credit);
                var banktransfer = new PaymentMethods();
                banktransfer.PaymentMethodName = "BANK_TRANSFER";
                banktransfer.PaymentMethodDescription = "BANK_TRANSFER";
                context.PaymentMethods.InsertOnSubmit(banktransfer);
                var cityledger = new PaymentMethods();
                cityledger.PaymentMethodName = "CITY_LEDGER";
                cityledger.PaymentMethodDescription = "CITY_LEDGER";
                context.PaymentMethods.InsertOnSubmit(cityledger);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            if (remarkEvents.Count == 0)
            {
                RemarkEvents remarkEventCheckIn = new RemarkEvents();
                remarkEventCheckIn.RemarkEventCode = "CHECKIN";
                remarkEventCheckIn.RemarkEventName = "CHECK_IN";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckIn);
                RemarkEvents remarkEventCheckOut = new RemarkEvents();
                remarkEventCheckOut.RemarkEventCode = "CHECKOUT";
                remarkEventCheckOut.RemarkEventName = "CHECK_OUT";
                context.RemarkEvents.InsertOnSubmit(remarkEventCheckOut);
                RemarkEvents remarkEventReservation = new RemarkEvents();
                remarkEventReservation.RemarkEventCode = "RESERVATION";
                remarkEventReservation.RemarkEventName = "RESERVATION";
                context.RemarkEvents.InsertOnSubmit(remarkEventReservation);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }

            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }*/
            var endTime = DateTime.Now;
            var retval = new
            {

                reservationRooms = reservationRooms,
                rooms = roomList,
                //roomBookingList = roomBookingList,
                BookingList = bookingList,
                //roomTypes = roomTypes,
                planList = planList,
                //statusColors = statusColors,
                //currencies = currencies,
                //currenciesISO = currenciesISO,
                //allResExtra = allResExtra,
                /*defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },*/
                //paymentMethods = paymentMethods,
                //remarkEvents = remarkEvents,
                //sourceList,
                //companyList,
                //marketList,
                executionTime = (endTime - currentTime).TotalMilliseconds,
                //AvailableRooms = AvailableRooms,
                //RelatedPayments = allRelatedPayments,
                //RoomMoves = allRoomMoves,
                //RoomExtraServicesList = allRoomExtraServiceList,
                //RoomExtraServiceItemsList = allRoomExtraServiceItemsList
            };
            memCache.Add("AppSTATUS_" + user.HotelId, retval, DateTimeOffset.UtcNow.AddHours(1));

            return Ok(retval);
        }



        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("Save")]
        public async Task<IHttpActionResult> SaveReservation(SaveRoomData data)
        {
            //return Ok( data );
            var user = Common.UserUtitily.getUserProfile();
            var context = new ezCloudDataContext();
            var responseOk = new
            {
                status = 201,
                ReservationRoomId = 0,
                mess = "",
            };
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();

            //UPDATE RESERVATION
            if (data.room != null && data.room.ReservationRoomId != 0 && data.room.ReservationRoomId != 0)
            {
                if (data.room.ArrivalDate != null && data.room.DepartureDate != null)
                {
                    if (data.room.RoomId > 0)
                    {
                        var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != data.room.ReservationRoomId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (data.room.BookingStatus == "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && DateTime.UtcNow <= r.DepartureDate)) || (data.room.BookingStatus != "CHECKIN" && (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate)))).FirstOrDefault();
                        if (conflictReservation != null)
                        {
                            ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                            //return Content(HttpStatusCode.BadRequest, conflictReservation);
                            responseOk = new
                            {
                                status = 201,
                                ReservationRoomId = conflictReservation.Reservations.ReservationNumber.Value,
                                mess = "CONFLICT_WITH_RESERVATION"
                            };
                            return Ok(responseOk);
                        }

                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                responseOk = new
                                {
                                    status = 201,
                                    ReservationRoomId = 0,
                                    mess = "CAN_NOT_CHECK_IN_REPAIRING_ROOM"
                                };
                                return Ok(responseOk);
                                //return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                responseOk = new
                                {
                                    status = 201,
                                    ReservationRoomId = 0,
                                    mess = "CAN_NOT_CHECK_IN_REPAIRING_ROOM"
                                };
                                return Ok(responseOk);
                                //return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        // var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == data.room.RoomId).FirstOrDefault();
                    }
                    ReservationRooms oldRR = context.ReservationRooms.Where(rr => rr.ReservationRoomId == data.room.ReservationRoomId && rr.HotelId == user.HotelId).FirstOrDefault();
                    if (oldRR != null)
                    {
                        CalculateRoomPrice model = new CalculateRoomPrice();
                        model.roomId = data.room.RoomId ?? 0;
                        model.reservationRoomId = data.room.ReservationRoomId;
                        model.adults = data.room.Adults;
                        model.children = data.room.Child;
                        model.RoomPriceId = data.room.RoomPriceId;
                        model.FOC = data.room.Foc;
                        model.DiscountFlat = data.room.DiscountFlat;
                        model.DiscountPercentage = (float)data.room.DiscountPercentage;
                        model.languageKeys = data.languageKeys;
                        model.Price = data.room.Price;

                        //if (data.room.BookingStatus == "CHECKIN")
                        //{
                        //    model.arrivalDate = DateTime.UtcNow;
                        //    model.departureDate = data.room.DepartureDate ?? default(DateTime);
                        //    Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + oldRR.Rooms.RoomName + " ", user.HotelId, "NOTIFICATION_CHECKEDIN");
                        //}

                        if (data.room.BookingStatus == "CHECKOUT")
                        {
                            var oldPastCheckOut = context.PastCheckOut.Where(pt => pt.HotelId == user.HotelId && pt.ReservationRoomId == data.room.ReservationRoomId).FirstOrDefault();
                            if (oldPastCheckOut != null)
                            {
                                if (data.room.DepartureDate >= DateTime.UtcNow)
                                {
                                    responseOk = new
                                    {
                                        status = 201,
                                        ReservationRoomId = 0,
                                        mess = "INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT",
                                    };
                                    return Ok(responseOk);
                                    //return BadRequest("INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT");
                                }
                                else
                                {
                                    model.departureDate = data.room.DepartureDate ?? default(DateTime);
                                }
                            }
                            else
                            {
                                model.departureDate = DateTime.UtcNow;
                            }
                            model.arrivalDate = data.room.ArrivalDate ?? default(DateTime);
                        }

                        // CHECK IN PROCESS
                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            oldRR.ArrivalDate = DateTime.UtcNow;
                            oldRR.DepartureDate = data.room.DepartureDate;
                            oldRR.Adults = data.room.Adults;
                            oldRR.Child = data.room.Child;
                            oldRR.RoomId = data.room.RoomId;
                            oldRR.Note = data.room.Note;
                            oldRR.BookingStatus = data.room.BookingStatus;
                            oldRR.Price = data.room.Price;
                            oldRR.Foc = data.room.Foc;
                            oldRR.DiscountPercentage = data.room.DiscountPercentage;
                            oldRR.DiscountFlat = data.room.DiscountFlat;
                            oldRR.CheckInDate = DateTime.UtcNow;
                            oldRR.CheckInUserId = user.UserId;
                            // Update Houstatus = AVAILABLE if Room is DIRTY
                            var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                            if (rooms != null)
                            {
                                rooms.HouseStatus = null;
                            }

                            if (data.company != null)
                            {
                                oldRR.Reservations.CompanyId = data.company.CompanyId;
                            }
                            if (data.source != null)
                            {
                                oldRR.Reservations.SourceId = data.source.SourceId;
                            }
                            if (data.market != null)
                            {
                                oldRR.Reservations.MarketId = data.market.MarketId;
                            }

                            var dateRange = new DateRange(oldRR.ArrivalDate.Value, oldRR.DepartureDate.Value);
                            ReservationUtility.RebuildRoomBreakfasts(dateRange, oldRR, user, context);
                            ReservationUtility.RebuildRoomCharges(dateRange, oldRR, user, context);
                            // NOTIFICATION
                            //Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + oldRR.Rooms.RoomName + " ", user.HotelId, "NOTIFICATION_CHECKEDIN");
                            Notification.processNotificationCheckin(user, oldRR.Rooms.RoomName);
                        }



                        context.SubmitChanges();
                        Common.Elastic.IndexLastAudit(context);

                        // Consider only if hotel is using module "Channel Mananger"
                        // Room Available
                        ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

                        responseOk = new
                        {
                            status = 200,
                            ReservationRoomId = data.room.ReservationRoomId,
                            mess = "Success",
                        };
                        return Ok(responseOk);
                        //return Ok(data.room.ReservationRoomId);
                    }
                    else
                    {
                        responseOk = new
                        {
                            status = 201,
                            ReservationRoomId = 0,
                            mess = "RESERVATION_DOES_NOT_EXIST",
                        };
                        return Ok(responseOk);
                    }
                        //return BadRequest("RESERVATION_DOES_NOT_EXIST");
                }
                else
                {
                    responseOk = new
                    {
                        status = 201,
                        ReservationRoomId = 0,
                        mess = "RESERVATION_DOES_NOT_EXIST",
                    };
                }
                return Ok(responseOk);
            }

            // NEW RESERVATION
            else
            {
                if (data.room.ArrivalDate != null && data.room.DepartureDate != null)
                {
                    if (data.room.RoomId > 0)
                    {
                        var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN" && data.room.BookingStatus == "CHECKIN") || (r.ArrivalDate < data.room.DepartureDate && data.room.ArrivalDate <= r.DepartureDate))).FirstOrDefault();
                        if (conflictReservation != null)
                        {
                            ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                            //return Content(HttpStatusCode.BadRequest, conflictReservation);
                            responseOk = new
                            {
                                status = 201,
                                ReservationRoomId = conflictReservation.Reservations.ReservationNumber.Value,
                                mess = "CONFLICT_WITH_RESERVATION"
                            };
                            return Ok(responseOk);
                        }

                        if (data.room.BookingStatus == "CHECKIN")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && DateTime.UtcNow <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                responseOk = new
                                {
                                    status = 201,
                                    ReservationRoomId = 0,
                                    mess = "CAN_NOT_CHECK_IN_REPAIRING_ROOM",
                                };
                                return Ok(responseOk);
                                //return BadRequest("CAN_NOT_CHECK_IN_REPAIRING_ROOM");
                            }
                        }

                        if (data.room.BookingStatus == "BOOKED")
                        {
                            var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == data.room.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= data.room.DepartureDate && data.room.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                            if (conflictRoomRepair != null)
                            {
                                responseOk = new
                                {
                                    status = 201,
                                    ReservationRoomId = 0,
                                    mess = "CAN_NOT_BOOK_TO_REPAIRING_ROOM",
                                };
                                return Ok(responseOk);
                                //return BadRequest("CAN_NOT_BOOK_TO_REPAIRING_ROOM");
                            }
                        }
                        var currentRoom = context.Rooms.Where(rm => rm.HotelId == user.HotelId && rm.RoomId == data.room.RoomId).FirstOrDefault();
                        if (currentRoom != null && currentRoom.HouseStatus == "REPAIR")
                        {
                            if (currentRoom.RepairStartDate == null)
                            {
                                currentRoom.RepairStartDate = ((DateTime)SqlDateTime.MinValue);
                            }
                            if (currentRoom.RepairEndDate == null)
                            {
                                currentRoom.RepairEndDate = ((DateTime)SqlDateTime.MaxValue);
                            }
                            if (currentRoom.RepairStartDate < data.room.DepartureDate && data.room.ArrivalDate <= currentRoom.RepairEndDate)
                            {
                                responseOk = new
                                {
                                    status = 201,
                                    ReservationRoomId = 0,
                                    mess = "CAN_NOT_PROCESS_REPAIRING_ROOM",
                                };
                                return Ok(responseOk);
                                //return BadRequest("CAN_NOT_PROCESS_REPAIRING_ROOM");
                            }
                        }
                    }
                    Reservations res = null;

                    //Create new
                    if (data.room != null && data.room.ReservationId != null && data.room.ReservationId > 0)
                    {
                        //Has reservation
                        res = context.Reservations.Where(r => r.ReservationId == data.room.ReservationId && r.HotelId == user.HotelId).FirstOrDefault();
                    }
                    if (res == null)
                    {
                        res = new Reservations();
                        res.HotelId = user.HotelId;
                        res.CreatedDate = DateTime.UtcNow;
                        res.ReservationNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATION");
                        context.Reservations.InsertOnSubmit(res);
                    }

                    if (data.source != null)
                    {
                        if (data.source.SourceId != 0)
                        {
                            res.SourceId = data.source.SourceId;
                        }
                        else
                        {
                            data.source.HotelId = user.HotelId;
                            data.source.CreatedDate = DateTime.UtcNow;
                            data.source.CreatedUserId = user.UserId;
                            data.source.IsAvailable = true;
                            context.Source.InsertOnSubmit(data.source);
                            res.Source = data.source;
                        }
                    }

                    if (data.company != null)
                    {
                        if (data.company.CompanyId != 0)
                        {
                            res.CompanyId = data.company.CompanyId;
                        }
                        else
                        {
                            data.company.HotelId = user.HotelId;
                            data.company.CreatedDate = DateTime.UtcNow;
                            data.company.CreatedUserId = user.UserId;
                            data.company.IsAvailable = true;
                            data.company.SourceId = data.company.SourceId != 0 ? data.company.SourceId : null;
                            context.Company.InsertOnSubmit(data.company);
                            res.Company = data.company;
                        }
                    }
                    if (data.market != null)
                    {
                        if (data.market.MarketId != 0)
                        {
                            res.MarketId = data.market.MarketId;
                        }
                        else
                        {
                            data.market.HotelId = user.HotelId;
                            data.market.CreatedDate = DateTime.UtcNow;
                            data.market.CreatedUserId = user.UserId;
                            data.market.IsAvailable = true;
                            context.Market.InsertOnSubmit(data.market);

                            res.Market = data.market;
                        }
                    }

                    data.room.Reservations = res;
                    data.room.HotelId = res.HotelId;
                    data.room.RoomId = (data.room.RoomId == 0) ? null : data.room.RoomId;
                    data.room.CreatedDate = DateTime.UtcNow;
                    data.room.CreatedUserId = user.UserId;
                    data.room.ReservationRoomNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATIONROOM");
                    if (data.room.BookingStatus == "CHECKIN")
                    {
                        // Update Houstatus = AVAILABLE if Room is DIRTY

                        var rooms = context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == data.room.RoomId && r.HouseStatus == "DIRTY").FirstOrDefault();
                        if (rooms != null)
                        {
                            rooms.HouseStatus = null;
                        }

                        data.room.ArrivalDate = DateTime.UtcNow;
                        data.room.CheckInDate = DateTime.UtcNow;
                        data.room.CheckInUserId = user.UserId;
                        //Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName + " ", user.HotelId, "NOTIFICATION_CHECKEDIN");
                    }

                    if (data.customer != null)
                    {
                        var insertedTraveller = new Travellers();
                        if (data.customer.TravellerId > 0)
                        {
                            data.room.TravellerId = data.customer.TravellerId;
                            Travellers oldTraveller = context.Travellers.Where(tv => tv.HotelId == user.HotelId && tv.TravellerId == data.room.TravellerId).FirstOrDefault();
                            oldTraveller.Email = data.customer.Email;
                            oldTraveller.Fullname = data.customer.Fullname;
                            oldTraveller.Mobile = data.customer.Mobile;
                            oldTraveller.Birthday = data.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                            oldTraveller.IdentityNumber = data.customer.IdentityNumber;
                            oldTraveller.Gender = data.customer.Gender;
                            oldTraveller.Address = data.customer.Address;
                            oldTraveller.CountryId = data.customer.CountryId;
                            oldTraveller.HotelId = user.HotelId;
                            oldTraveller.ModifiedUserId = user.UserId;
                            oldTraveller.ModifiedDate = DateTime.UtcNow;
                            insertedTraveller = oldTraveller;
                        }
                        else
                        {
                            data.customer.HotelId = user.HotelId;
                            data.customer.Birthday = data.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                            data.customer.CreatedDate = DateTime.UtcNow;
                            data.customer.CreatedUserId = user.UserId;
                            if (data.customer.CountryId == null)
                            {
                                var country = context.Countries.First(c => c.CountryCode.ToLower() == "vn");
                                if (country != null)
                                {
                                    data.customer.CountryId = country.CountryId;
                                }
                            }
                            context.Travellers.InsertOnSubmit(data.customer);
                            insertedTraveller = data.customer;
                            data.room.Travellers = insertedTraveller;
                        }

                        context.ReservationRooms.InsertOnSubmit(data.room);

                        ReservationTravellers resTraveller = new ReservationTravellers();
                        resTraveller.ReservationRooms = data.room;
                        resTraveller.Travellers = insertedTraveller;
                        context.ReservationTravellers.InsertOnSubmit(resTraveller);

                        ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                        newRTEI.HotelId = user.HotelId;
                        newRTEI.ReservationTravellers = resTraveller;
                        newRTEI.IsChild = false;
                        context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                    }

                    if (data.sharerList != null && data.sharerList.Count > 0)
                    {
                        for (int i = 0; i < data.sharerList.Count; i++)
                        {
                            SharerViewModel sharerTemp = data.sharerList[i];
                            if (sharerTemp.customer.TravellerId == 0)
                            {
                                sharerTemp.customer.HotelId = user.HotelId;
                                sharerTemp.customer.CreatedUserId = user.UserId;
                                sharerTemp.customer.CreatedDate = DateTime.UtcNow;
                                context.Travellers.InsertOnSubmit(sharerTemp.customer);
                            }
                            else
                            {
                                Travellers oldSharer = context.Travellers.Where(tv => tv.HotelId == user.HotelId && tv.TravellerId == sharerTemp.customer.TravellerId).FirstOrDefault();
                                oldSharer.Email = sharerTemp.customer.Email;
                                oldSharer.Fullname = sharerTemp.customer.Fullname;
                                oldSharer.Mobile = sharerTemp.customer.Mobile;
                                oldSharer.Birthday = sharerTemp.customer.Birthday.HasValue ? data.customer.Birthday.Value.AddHours(currentHotel.TimeZoneOffset / 60) : (DateTime)SqlDateTime.MinValue;
                                oldSharer.IdentityNumber = sharerTemp.customer.IdentityNumber;
                                oldSharer.Gender = sharerTemp.customer.Gender;
                                oldSharer.Address = sharerTemp.customer.Address;
                                oldSharer.CountryId = sharerTemp.customer.CountryId;
                                oldSharer.ModifiedDate = DateTime.UtcNow;
                                oldSharer.ModifiedUserId = user.UserId;
                            }

                            ReservationTravellers newRT = new ReservationTravellers();
                            newRT.ReservationRoomId = data.room.ReservationRoomId;
                            newRT.Travellers = sharerTemp.customer;
                            context.ReservationTravellers.InsertOnSubmit(newRT);

                            ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                            newRTEI.HotelId = user.HotelId;
                            newRTEI.ReservationTravellers = newRT;
                            newRTEI.IsChild = sharerTemp.travellerExtraInfo.IsChild;
                            context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                        }
                    }

                    if (data.room.RoomPriceId == 0)
                    {
                        data.room.RoomPriceId = (int?)null;
                    }
                    if (data.room.RoomId == 0)
                    {
                        data.room.RoomId = (int?)null;
                    }
                    if (data.room.RoomTypeId == 0)
                    {
                        data.room.RoomTypeId = (int?)null;
                    }
                    if (data.paymentList != null && data.paymentList.Count > 0)
                    {
                        var moneyList = context.Money.Where(ht => ht.HotelId == user.HotelId).ToList();
                        var paymentMethodList = context.PaymentMethods.Where(pm => pm.PaymentMethodId == pm.PaymentMethodId).ToList();
                        foreach (var payment in data.paymentList)
                        {
                            payment.ReservationRooms = data.room;
                            payment.CreatedUserId = user.UserId;
                            payment.HotelId = user.HotelId;
                            payment.Money = moneyList.FirstOrDefault(mn => mn.MoneyId == payment.MoneyId);
                            payment.PaymentMethods = paymentMethodList.FirstOrDefault(pm => pm.PaymentMethodId == payment.PaymentMethodId);
                            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
                            {
                                payment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, payment.PaymentTypeName);
                                /*
                                var paymentMessage = "";

                                if (payment.PaymentTypeName == "NEW_PAYMENT")
                                {
                                    paymentMessage = data.languageKeys["NOTIFICATION_NEWPAYMENT"] != null ? data.languageKeys["NOTIFICATION_NEWPAYMENT"].ToString() : "";
                                }
                                else if (payment.PaymentTypeName == "DEPOSIT")
                                {
                                    paymentMessage = data.languageKeys["NOTIFICATION_DEPOSIT"] != null ? data.languageKeys["NOTIFICATION_DEPOSIT"].ToString() : "";
                                }
                                else if (payment.PaymentTypeName == "REFUND")
                                {
                                    paymentMessage = data.languageKeys["NOTIFICATION_REFUND"] != null ? data.languageKeys["NOTIFICATION_REFUND"].ToString() : "";
                                }
                                //var ReservationNumber = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationRoomId == payment.ReservationRoomId).Join(context.Reservations, r => r.ReservationId, p => p.ReservationId, (r, p) => new { r.Reservations.ReservationNumber }).FirstOrDefault().ReservationNumber;
                                var ReservationNumber = res.ReservationNumber;
                                //var money = context.Money.Where(m => m.HotelId == user.HotelId && m.MoneyId == payment.MoneyId).FirstOrDefault().MoneyName;
                                var money = payment.Money.MoneyName;
                                //var paymethodname = context.PaymentMethods.Where(m => m.PaymentMethodId == payment.PaymentMethodId).FirstOrDefault().PaymentMethodName;
                                var paymethodname = payment.PaymentMethods.PaymentMethodName;
                                //var rooms = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == payment.ReservationRoomId).FirstOrDefault().RoomId;
                                var rooms = data.room.Rooms;
                                var roomName = "";
                                //roomName = roomName != null ? roomName : ReservationNumber.ToString();
                                //var roomName = roomId != null ? context.Rooms.Where(r => r.HotelId == user.HotelId && r.RoomId == roomId).FirstOrDefault().RoomName : ReservationNumber.ToString();
                                var room_resno = "";
                                if (rooms != null)
                                {
                                    roomName = rooms.RoomName;
                                    room_resno = data.languageKeys["ROOM"] != null ? data.languageKeys["ROOM"].ToString() : "";
                                }
                                else
                                {
                                    roomName = ReservationNumber.ToString();
                                    room_resno = data.languageKeys["RES_NO"] != null ? data.languageKeys["RES_NO"].ToString() : "";
                                }
                                paymentMessage = paymentMessage.Replace("[USER]", user.FullName);
                                paymentMessage = paymentMessage.ToString().Replace("[PAYMENTMETHOD]", data.languageKeys[paymethodname] != null ? data.languageKeys[paymethodname].ToString() : "");
                                var spaymentAmount = Math.Abs(Convert.ToDecimal(payment.Amount)).ToString("c", Utilities.GetCurrencyFormatProviderSymbolDecimals(money));
                                paymentMessage = paymentMessage.ToString().Replace("[MONEY]", money + " " + spaymentAmount);
                                paymentMessage = paymentMessage.ToString().Replace("[ROOM]", roomName);
                                paymentMessage = paymentMessage.ToString().Replace("[ROOM_RESNO]", room_resno);
                                Notification.sendNotificationToDevice(user.UserName.ToLower(), paymentMessage, user.HotelId, "NOTIFICATION_WHEN_POST_PAYMENT");
                                */

                            }
                            context.Payments.InsertOnSubmit(payment);
                        }
                    }

                    if (data.roomRemarks != null && data.roomRemarks.Count > 0)
                    {
                        for (int i = 0; i < data.roomRemarks.Count; i++)
                        {
                            RoomRemarks roomRemark = new RoomRemarks();
                            roomRemark.HotelId = user.HotelId;
                            roomRemark.ReservationRooms = data.room;
                            roomRemark.RemarkEventId = data.roomRemarks[i].RemarkEventId;
                            roomRemark.Description = data.roomRemarks[i].Description;
                            roomRemark.IsCompleted = data.roomRemarks[i].IsCompleted;
                            roomRemark.IsDeleted = data.roomRemarks[i].IsDeleted;
                            roomRemark.CreatedDate = data.roomRemarks[i].CreatedDate;
                            roomRemark.CreatedUserId = user.UserId;
                            context.RoomRemarks.InsertOnSubmit(roomRemark);
                        }
                    }

                    var dateRange = new DateRange(data.room.ArrivalDate.Value, data.room.DepartureDate.Value);
                    ReservationUtility.CreateRoomBreakfasts(dateRange, data.room, user, context);
                    ReservationUtility.CreateRoomCharges(dateRange, data.room, user, context);

                    if (data.postedItems != null && data.postedItems.ReservationRoomId == 0)
                    {
                        var roomExtraService = new RoomExtraServices();
                        roomExtraService.RoomExtraServiceName = data.postedItems.name;
                        roomExtraService.RoomExtraServiceDescription = data.postedItems.description;
                        roomExtraService.HotelId = user.HotelId;
                        roomExtraService.IsPaid = false;
                        roomExtraService.ReservationRoomId = data.postedItems.ReservationRoomId;
                        roomExtraService.CreatedUserId = user.UserId;
                        roomExtraService.CreatedDate = DateTime.UtcNow;
                        roomExtraService.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, roomExtraService.RoomExtraServiceName);
                        int count = 0;
                        decimal totalMoney = 0;
                        List<RoomExtraServiceItems> newItems = new List<RoomExtraServiceItems>();
                        var serviceItemList = "";
                        foreach (SelectedServiceItem item in data.postedItems.items)
                        {
                            var realItem = context.ExtraServiceItems.Where(it => it.HotelId == user.HotelId && it.ExtraServiceItemId == item.item.ExtraServiceItemId).FirstOrDefault();
                            if (realItem != null)
                            {
                                count++;
                                totalMoney += (decimal)realItem.Price * item.quantity;
                                RoomExtraServiceItems ritem = new RoomExtraServiceItems();
                                ritem.Quantity = item.quantity;
                                ritem.ExtraServiceItemId = realItem.ExtraServiceItemId;
                                ritem.HotelId = realItem.HotelId;
                                ritem.Price = realItem.Price;
                                ritem.ReservationRoomId = data.postedItems.ReservationRoomId;
                                newItems.Add(ritem);
                                serviceItemList = serviceItemList + realItem.ExtraServiceItemName + "(" + item.quantity.ToString() + ") ";
                            }
                        }
                        if (count == 0) {
                            responseOk = new
                            {
                                status = 201,
                                ReservationRoomId = 0,
                                mess = "No items selected",
                            };
                            return Ok(responseOk);
                        } 
                        //return BadRequest("No items selected");
                        roomExtraService.Amount = totalMoney;
                        context.RoomExtraServices.InsertOnSubmit(roomExtraService);
                    }

                    if (data.postedNoItem != null && data.postedNoItem.Count > 0)
                    {
                        foreach (var item in data.postedNoItem)
                        {
                            var resNoItem = new RoomExtraServices();
                            resNoItem.RoomExtraServiceName = item.RoomExtraServiceName;
                            resNoItem.RoomExtraServiceDescription = item.RoomExtraServiceDescription;
                            resNoItem.Amount = item.Amount;
                            resNoItem.Quantity = item.Quantity == 0? 1 : item.Quantity;
                            resNoItem.HotelId = user.HotelId;
                            resNoItem.IsPaid = false;
                            resNoItem.ReservationRooms = data.room;
                            resNoItem.CreatedUserId = user.UserId;
                            resNoItem.CreatedDate = DateTime.UtcNow;
                            resNoItem.RoomExtraServiceNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "EXTRA_SERVICES");
                            context.RoomExtraServices.InsertOnSubmit(resNoItem);
                        }
                    }


                    context.SubmitChanges();


                    Elastic.IndexLastAudit(context);

                    // Consider only if hotel is using module "Channel Mananger"
                    // Room Available
                    ReservationUtility.RebuildAvailableRoom(data.room, user, context);
                    //send notification if have payments
                    if (data.paymentList != null && data.paymentList.Count > 0)
                    {
                        foreach (var payment in data.paymentList)
                        {

                            if (payment.PaymentTypeName != "DELETED" || payment.RefPaymentId == null)
                            {
                                PaymentModel paymentsModel = new PaymentModel();
                                paymentsModel.languageKeys = data.languageKeys;
                                paymentsModel.payment = payment;

                                Notification.processNotificationAddNewPayment(paymentsModel, user);
                            }

                        }
                    }

                    if (data.room.BookingStatus == "CHECKIN")
                    {
                        Notification.processNotificationCheckin(user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName);
                    }
                    else if (data.room.BookingStatus == "BOOKED")
                    {
                         
                        if ( !data.room.RoomId.HasValue )
                        { 
                            Notification.processNotificationBookedNan( user, res.ReservationNumber.Value, data.customer.Fullname, data.languageKeys["NOTIFICATION_BOOKED_NAN_CONTENT"].ToString() );
                        }else
                        {

                            Notification.processNotificationBooked(user, context.Rooms.Where(R => R.HotelId == user.HotelId && R.RoomId == data.room.RoomId).FirstOrDefault().RoomName, (int)res.ReservationNumber, data.customer.Fullname, data.languageKeys["NOTIFICATION_BOOKED_CONTENT"].ToString());
                        }
                    }


                    responseOk = new
                    {
                        status = 200,
                        ReservationRoomId = res.ReservationNumber.Value,
                        mess = "Success",
                    };
                    return Ok(responseOk);
                    //return Ok(data.room.ReservationRoomId);
                }
                else
                {
                    responseOk = new
                    {
                        status = 201,
                        ReservationRoomId = 0,
                        mess = "Please select arrival/departure date!",
                    };
                    //return BadRequest("Please select arrival/departure date!");
                }
                return Ok( responseOk );
            }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAssignRoom")]
        public async Task<IHttpActionResult> ProcessAssignRoom(ReservationRooms model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var context = new ezCloudDataContext();
            var user = Common.UserUtitily.getUserProfile();
            var oldRR =
                context.ReservationRooms.FirstOrDefault(
                    rr => rr.HotelId == user.HotelId && rr.ReservationRoomNumber == model.ReservationRoomNumber);
            if (oldRR != null)
            {
                //ReservationRooms orgOldRR = oldRR.; // for process CMS 
                var arrivalDate = oldRR.ArrivalDate;
                var departureDate = oldRR.DepartureDate;
                var roomTypeId = oldRR.RoomTypeId;

                var conflictReservation = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.RoomId == model.RoomId && r.ReservationRoomId != oldRR.ReservationRoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && (r.ArrivalDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= r.DepartureDate)).FirstOrDefault();
                if (conflictReservation != null)
                {
                    ObjectExtensions.AddProperty(conflictReservation, "reservationNumber", conflictReservation.Reservations.ReservationNumber);
                    //return Content(HttpStatusCode.BadRequest, conflictReservation);
                    return Ok(new
                    {
                        status = 201,
                        ReservationRoomId = conflictReservation.ReservationRoomNumber.Value,
                        mess = "CONFLICT_WITH_RESERVATION",
                    });
                }
                var conflictRoomRepair = context.RoomRepair.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == model.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= oldRR.DepartureDate && oldRR.ArrivalDate <= rr.RepairEndDate)).FirstOrDefault();
                if (conflictRoomRepair != null)
                {
                     
                    return Ok(new
                    {
                        status = 201,
                        ReservationRoomId = 0,
                        mess = "CAN_NOT_ASSIGN_ROOM_IN_REPAIRING_TIME",
                    });
                    //return BadRequest("CAN_NOT_ASSIGN_ROOM_IN_REPAIRING_TIME");
                }
                oldRR.RoomTypeId = model.RoomTypeId;
                oldRR.RoomPriceId = model.RoomPriceId;
                oldRR.Price = model.Price;
                oldRR.RoomId = model.RoomId != 0 ? model.RoomId : null;
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);

                // Consider only if hotel is using module "Channel Mananger"
                // Room Available
                ReservationUtility.RebuildAvailableRoom(oldRR, user, context);

                // Update matrix for original period 
                var RRTemp = new ReservationRooms();
                RRTemp.ArrivalDate = arrivalDate;
                RRTemp.DepartureDate = departureDate;
                RRTemp.RoomTypeId = roomTypeId;
                ReservationUtility.RebuildAvailableRoom(RRTemp, user, context);
            }
            var cache = new
            {
                status = 200,
                ReservationRoomId = 0,
                mess = "Success",
            };
            return Ok(cache);
        }


        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetAvailabilityMatrixData")]
        public async Task<IHttpActionResult> GetAvailabilityMatrixData(DateTime from, DateTime to)
        {
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);

            from = from.AddMinutes(-currentHotel.TimeZoneOffset);
            to = to.AddMinutes(-currentHotel.TimeZoneOffset);
            
            var cmRoomTypeMapping = context.RoomTypes
                                                .Where(rt => rt.HotelId == user.HotelId && rt.IsHidden == false)
                                                .GroupJoin(
                                                    context.CMRoomTypeMappings
                                                        .Where(cmrt => cmrt.HotelId == user.HotelId && cmrt.IsDeleted == false ), 
                                                        rt => rt.RoomTypeId, 
                                                        cmrt => cmrt.RoomTypeId, 
                                                        (rt, cmrt) => new {
                                                                rt,
                                                                cmrt = cmrt.First(),
                                                        })
                                                .ToList();
            var cmAvailabilityMatrix = context.CMAvailabilityMatrixs.Where(av => av.HotelId == user.HotelId && from <= av.MatrixDate && av.MatrixDate <= to).ToList();
            var RoomAvailabilityMatrix = Utilities.GetRoomAvailabilityMatrix(from, to);
            return Ok(new
            {
                cmRoomTypeMapping,
                cmAvailabilityMatrix,
                RoomAvailabilityMatrix,
                CMConfiguration = currentHotel.CMConfigurationsList.FirstOrDefault()
            });
        }



        public class EditCheckInTimeModel
        {
            public int ReservationRoomId { get; set; }
            public DateTime NewArrivalDate { get; set; }
        }

        public class DashboardApp
        {
            // Thông kê hôm nay
            public int todayStats_roomOccupied { get; set; }

            public int todayStats_roomDueOut { get; set; }
            public int todayStats_roomTodayStayOver { get; set; }
            public int todayStats_roomArrival { get; set; }
            public int todayStats_roomTotalRoomsToSell { get; set; }

            public int todayStats_Projected_roomOccupied { get; set; } //{{todayStats.roomOccupied+todayStats.roomArrival}}

            public double todayStats_Projected_Occupancy { get; set; } //{{ ( (todayStats.roomOccupied+todayStats.roomArrival-todayStats.roomDueOut+todayActivity.Day_Use)*100/todayStats.roomTotalRoomsToSell).toFixed(2); }}

            // Hoạt động trong ngày

            public int todayActivity_Arrived { get; set; }

            public int todayActivity_Due_To_Arrive { get; set; }
            public int todayActivity_Checked_Out { get; set; }
            public int todayActivity_Due_Out { get; set; }
            public int todayActivity_Day_Use { get; set; }

            // Tong khach dang o
            public int hotelGuests_Expected_In_House_Children { get; set; }

            public int hotelGuests_Expected_In_House_Adult { get; set; }

            public decimal Total_Revenue { get; set; }
            public decimal Total_Payment { get; set; }
        }


    }



    

}